﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace CodeFarmer.Core
{
    public static class StringExtension
    {

        /// <summary>
        /// 获取字符串的实际长度(按单字节)
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static int GetRealLength(this string source)
        {
            return Encoding.Default.GetByteCount(source);
        }
        /// <summary>
        /// 取得固定长度的字符串(按单字节截取)。
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="resultLength">截取长度</param>
        /// <returns></returns>
        public static string SubString(this string source, int resultLength)
        {
            if (Encoding.Default.GetByteCount(source) > resultLength)
            {
                if (source == null)
                {
                    return "";
                }
                int i = 0;
                int j = 0;
                string text = source;
                for (int k = 0; k < text.Length; k++)
                {
                    char newChar = text[k];
                    if (newChar > '\u007f')
                    {
                        i += 2;
                    }
                    else
                    {
                        i++;
                    }
                    if (i > resultLength)
                    {
                        source = source.Substring(0, j);
                        break;
                    }
                    j++;
                }
            }
            return source;
        }
        /// <summary>
        /// 取得固定长度字符的字符串，后面加上…(按单字节截取)
        /// </summary>
        /// <param name="source"></param>
        /// <param name="resultLength"></param>
        /// <returns></returns>
        public static string SubStr(this string source, int resultLength)
        {
            if (string.IsNullOrEmpty(source))
            {
                return "";
            }
            if (source.GetRealLength() <= resultLength)
            {
                return source;
            }
            return source.SubString(resultLength) + "...";
        }
        /// <summary>
        /// 判断字符串是否为null或为空.判断为空操作前先进行了Trim操作。
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool IsNullOrEmpty(this string source)
        {
            return source == null || source.Trim().Length < 1;
        }
        /// <summary>
        /// 判断字符串是否为整型
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool IsInteger(this string source)
        {
            int i;
            return !string.IsNullOrEmpty(source) && int.TryParse(source, out i);
        }
        /// <summary>
        /// Email 格式是否合法
        /// </summary>
        /// <param name="source"></param>
        public static bool IsEmail(this string source)
        {
            return Regex.IsMatch(source, "^\\w+((-\\w+)|(\\.\\w+))*\\@[A-Za-z0-9]+((\\.|-)[A-Za-z0-9]+)*\\.[A-Za-z0-9]+$");
        }
        /// <summary>
        /// 判断是否IP
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool IsIP(this string source)
        {
            return Regex.IsMatch(source, "^(((25[0-5]|2[0-4][0-9]|19[0-1]|19[3-9]|18[0-9]|17[0-1]|17[3-9]|1[0-6][0-9]|1[1-9]|[2-9][0-9]|[0-9])\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]))|(192\\.(25[0-5]|2[0-4][0-9]|16[0-7]|169|1[0-5][0-9]|1[7-9][0-9]|[1-9][0-9]|[0-9]))|(172\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|1[0-5]|3[2-9]|[4-9][0-9]|[0-9])))\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$");
        }
        /// <summary>
        /// 检查字符串是否为A-Z、0-9及下划线以内的字符
        /// </summary>
        /// <param name="source">被检查的字符串</param>
        /// <returns>是否有特殊字符</returns>
        public static bool IsLetterOrNumber(this string source)
        {
            return Regex.IsMatch(source, "\\w");
        }
        /// <summary>
        /// 验输入字符串是否含有“/\:.?*|$]”特殊字符
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool IsSpecialChar(this string source)
        {
            Regex r = new Regex("[/\\<>:.?*|$]");
            return r.IsMatch(source);
        }
        /// <summary>
        /// 是否全为中文/日文/韩文字符
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <returns></returns>
        public static bool IsChineseChar(this string source)
        {
            return Regex.IsMatch(source, "^[\\u4E00-\\u9FA5]+$");
        }
        /// <summary>
        /// 是否包含双字节字符(允许有单字节字符)
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool IsDoubleChar(this string source)
        {
            return Regex.IsMatch(source, "[^\\x00-\\xff]");
        }
        /// <summary>
        /// 是否为日期型字符串
        /// </summary>
        /// <param name="source">日期字符串(2005-6-30)</param>
        /// <returns></returns>
        public static bool IsDate(this string source)
        {
            return Regex.IsMatch(source, "^((((1[6-9]|[2-9]\\d)\\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\\d|3[01]))|(((1[6-9]|[2-9]\\d)\\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\\d|30))|(((1[6-9]|[2-9]\\d)\\d{2})-0?2-(0?[1-9]|1\\d|2[0-8]))|(((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-))$");
        }
        /// <summary>
        /// 是否为时间型字符串
        /// </summary>
        /// <param name="source">时间字符串(15:00:00)</param>
        /// <returns></returns>
        public static bool IsTime(this string source)
        {
            return Regex.IsMatch(source, "^((20|21|22|23|[0-1]?\\d):[0-5]?\\d:[0-5]?\\d)$");
        }
        /// <summary>
        /// 是否为日期+时间型字符串
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool IsDateTime(this string source)
        {
            return Regex.IsMatch(source, "^(((((1[6-9]|[2-9]\\d)\\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\\d|3[01]))|(((1[6-9]|[2-9]\\d)\\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\\d|30))|(((1[6-9]|[2-9]\\d)\\d{2})-0?2-(0?[1-9]|1\\d|2[0-8]))|(((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-)) (20|21|22|23|[0-1]?\\d):[0-5]?\\d:[0-5]?\\d)$");
        }
        /// <summary>
        /// 将字符串使用base64算法加密
        /// </summary>
        /// <param name="source">待加密的字符串</param>
        /// <returns>加码后的文本字符串</returns>
        public static string ToBase64(this string source)
        {
            return Convert.ToBase64String(Encoding.Default.GetBytes(source));
        }
        /// <summary>
        /// 从Base64编码的字符串中还原字符串，支持中文
        /// </summary>
        /// <param name="source">Base64加密后的字符串</param>
        /// <returns>还原后的文本字符串</returns>
        public static string FromBase64(this string source)
        {
            return Encoding.Default.GetString(Convert.FromBase64String(source));
        }
        /// <summary>
        /// 将 GB2312 值转换为 UTF8 字符串(如：测试 -&gt; 娴嬭瘯 )
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string FromGBToUTF8(this string source)
        {
            return Encoding.GetEncoding("GB2312").GetString(Encoding.UTF8.GetBytes(source));
        }
        /// <summary>
        /// 将 UTF8 值转换为 GB2312 字符串 (如：娴嬭瘯 -&gt; 测试)
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string FromUTF8ToGB(this string source)
        {
            return Encoding.UTF8.GetString(Encoding.GetEncoding("GB2312").GetBytes(source));
        }
        /// <summary>
        /// 由16进制转为汉字字符串（如：B2E2 -&gt; 测 ）
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string FromHex(this string source)
        {
            byte[] oribyte = new byte[source.Length / 2];
            for (int i = 0; i < source.Length; i += 2)
            {
                Convert.ToInt32(source.Substring(i, 2), 16).ToString();
                oribyte[i / 2] = Convert.ToByte(source.Substring(i, 2), 16);
            }
            return Encoding.Default.GetString(oribyte);
        }
        /// <summary>
        /// 字符串转为16进制字符串（如：测 -&gt; B2E2 ）
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string ToHex(this string source)
        {
            int i = source.Length;
            string end = "";
            byte[] array = new byte[2];
            for (int j = 0; j < i; j++)
            {
                string temp = source.Substring(j, 1);
                array = Encoding.Default.GetBytes(temp);
                if (array.Length.ToString() == "1")
                {
                    int i2 = Convert.ToInt32(array[0]);
                    end += Convert.ToString(i2, 16);
                }
                else
                {
                    int i2 = Convert.ToInt32(array[0]);
                    int i3 = Convert.ToInt32(array[1]);
                    end += Convert.ToString(i2, 16);
                    end += Convert.ToString(i3, 16);
                }
            }
            return end.ToUpper();
        }
        /// <summary>
        /// 字符串转为unicode字符串（如：测试 -&gt; 测试）
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string ToUnicode(this string source)
        {
            StringBuilder sa = new StringBuilder();
            for (int i = 0; i < source.Length; i++)
            {
                byte[] bt = Encoding.Unicode.GetBytes(source.Substring(i, 1));
                if (bt.Length > 1)
                {
                    string s = Convert.ToString((short)bt[1], 16);
                    string s2 = Convert.ToString((short)bt[0], 16);
                    s = ((s.Length == 1) ? "0" : "") + s;
                    s2 = ((s2.Length == 1) ? "0" : "") + s2;
                    sa.Append("&#" + Convert.ToInt32(s + s2, 16) + ";");
                }
            }
            return sa.ToString();
        }
        /// <summary>
        /// 字符串转为UTF8字符串（如：测试 -&gt; \u6d4b\u8bd5）
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string ToUTF8(this string source)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < source.Length; i++)
            {
                byte[] bt = Encoding.Unicode.GetBytes(source.Substring(i, 1));
                if (bt.Length > 1)
                {
                    string s = Convert.ToString((short)bt[1], 16);
                    string s2 = Convert.ToString((short)bt[0], 16);
                    s = ((s.Length == 1) ? "0" : "") + s;
                    s2 = ((s2.Length == 1) ? "0" : "") + s2;
                    sb.Append("\\u" + s + s2);
                }
            }
            return sb.ToString();
        }
        /// <summary>
        /// 将字符串转为安全的Sql字符串，不建议使用。尽可能使用参数化查询来避免
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string ToSafeSql(this string source)
        {
            if (string.IsNullOrEmpty(source))
            {
                return string.Empty;
            }
            return source.Replace("'", "''");
        }
        /// <summary>
        /// 将字符串转换化安全的js字符串值（对字符串中的' "进行转义) 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string ToSafeJsString(this string source)
        {
            source = source.Replace("'", "\\'");
            source = source.Replace("\"", "\\\"");
            source = source.Replace("\r\n", "").Replace("\r", "").Replace("\n", "");
            return source;
        }
        /// <summary>
        /// 注释like操作字符串中出现的特殊符号
        /// </summary>
        /// <remarks>注意：如果like查询中本身有使用到特殊字符，请不要使用此方法</remarks>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string ToEscapeRegChars(this string source)
        {
            source = source.Replace("[", "[[]");
            source = source.Replace("%", "[%]");
            source = source.Replace("_", "[_]");
            source = source.Replace("^", "[^]");
            return source;
        }
        /// <summary>
        /// 将字符串包装成 &lt;![CDATA[字符串]]&gt; 形式
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string WrapWithCData(this string source)
        {
            return string.Format("<![CDATA[{0}]]>", source);
        }
        /// <summary>
        /// 将字符串转换化安全的XML字符串值
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string ToSafeXmlString(this string source)
        {
            return source.Replace(">", "&gt;").Replace("<", "&lt;").Replace("&", "&amp;").Replace("\"", "&quot;").Replace("'", "&apos;");
        }
        /// <summary>
        /// 将字符串转成Int32类型，如果转换失败，则返回-1
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <returns></returns>
        public static int ToInt32(this string source)
        {
            return source.ToInt32(-1);
        }
        /// <summary>
        /// 将字符串转成Int32类型
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="defaultValue">如果转换失败，返回的数值</param>
        /// <returns></returns>
        public static int ToInt32(this string source, int defaultValue)
        {
            int result;
            if (!string.IsNullOrEmpty(source) && int.TryParse(source, out result))
            {
                return result;
            }
            return defaultValue;
        }
        /// <summary>
        /// 将字符串转成Int64类型，如果转换失败，则返回-1
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <returns></returns>
        public static long ToInt64(this string source)
        {
            return source.ToInt64(-1L);
        }
        /// <summary>
        /// 将字符串转成Int64类型
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="defaultValue">如果转换失败，返回的数值</param>
        /// <returns></returns>
        public static long ToInt64(this string source, long defaultValue)
        {
            long result;
            if (!string.IsNullOrEmpty(source) && long.TryParse(source, out result))
            {
                return result;
            }
            return defaultValue;
        }
        /// <summary>
        /// 将字符串转成double类型，如果转换失败，则返回-1
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <returns></returns>
        public static double ToDouble(this string source)
        {
            return source.ToDouble(-1.0);
        }
        /// <summary>
        /// 将字符串转成double类型
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="defaultValue">如果转换失败，返回的数值</param>
        /// <returns></returns>
        public static double ToDouble(this string source, double defaultValue)
        {
            double result;
            if (!string.IsNullOrEmpty(source) && double.TryParse(source, out result))
            {
                return result;
            }
            return defaultValue;
        }
        /// <summary>
        /// 将字符串转成DateTime类型，如果转换失败，则返回当前时间
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <returns></returns>
        public static DateTime ToDateTime(this string source)
        {
            return source.ToDateTime(DateTime.Now);
        }
        /// <summary>
        /// 将字符串转成DateTime类型
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="defaultValue">如果转换失败，返回的默认时间</param>
        /// <returns></returns>
        public static DateTime ToDateTime(this string source, DateTime defaultValue)
        {
            DateTime result;
            if (!string.IsNullOrEmpty(source) && DateTime.TryParse(source, out result))
            {
                return result;
            }
            return defaultValue;
        }
        /// <summary>
        /// 将字符串转成Boolean类型，如果转换失败，则返回false
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <returns></returns>
        public static bool ToBoolean(this string source)
        {
            bool result;
            return !string.IsNullOrEmpty(source) && bool.TryParse(source, out result) && result;
        }
        /// <summary>
        /// 将字符串转成指定的枚举类型(字符串可以是枚举的名称也可以是枚举值)
        /// </summary>
        /// <typeparam name="T">枚举类型</typeparam>
        /// <param name="source">源字符串</param>
        /// <param name="defaultValue">如果转换失败，返回默认的枚举项</param>
        /// <returns></returns>
        public static T ToEnum<T>(this string source, T defaultValue)
        {
            if (!string.IsNullOrEmpty(source))
            {
                try
                {
                    T value = (T)Enum.Parse(typeof(T), source, true);
                    if (Enum.IsDefined(typeof(T), value))
                    {
                        return value;
                    }
                }
                catch
                {
                }
                return defaultValue;
            }
            return defaultValue;
        }
        /// <summary>
        /// 将字符串转成指定的枚举类型(字符串可以是枚举的名称也可以是枚举值)
        /// <remarks>支持枚举值的并集</remarks>
        /// </summary>
        /// <typeparam name="T">枚举类型</typeparam>
        /// <param name="source">源字符串</param>
        /// <param name="defaultValue">如果转换失败，返回默认的枚举项</param>
        /// <returns></returns>
        public static T ToEnumExt<T>(this string source, T defaultValue)
        {
            if (!string.IsNullOrEmpty(source))
            {
                try
                {
                    return (T)Enum.Parse(typeof(T), source, true);
                }
                catch
                {
                }
                return defaultValue;
            }
            return defaultValue;
        }
        /// <summary>
        /// 获取汉字字符串的首字母
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string GetPinYin(this string source)
        {
            return StringExtension.GetChineseSpell(source);
        }
        /// <summary>
        /// 取得汉字字符串的拼音的首字母
        /// </summary>
        /// <param name="strText"></param>
        /// <returns></returns>
        private static string GetChineseSpell(string strText)
        {
            int len = strText.Length;
            string myStr = "";
            for (int i = 0; i < len; i++)
            {
                myStr += StringExtension.getSpell(strText.Substring(i, 1));
            }
            return myStr;
        }
        /// <summary>
        /// 取得汉字字符的拼音的首字母
        /// </summary>
        /// <param name="cnChar"></param>
        /// <returns></returns>
        private static string getSpell(string cnChar)
        {
            byte[] arrCN = Encoding.Default.GetBytes(cnChar);
            if (arrCN.Length > 1)
            {
                int area = (int)arrCN[0];
                int pos = (int)arrCN[1];
                int code = (area << 8) + pos;
                int[] areacode = new int[]
				{
					45217,
					45253,
					45761,
					46318,
					46826,
					47010,
					47297,
					47614,
					48119,
					48119,
					49062,
					49324,
					49896,
					50371,
					50614,
					50622,
					50906,
					51387,
					51446,
					52218,
					52698,
					52698,
					52698,
					52980,
					53689,
					54481
				};
                for (int i = 0; i < 26; i++)
                {
                    int max = 55290;
                    if (i != 25)
                    {
                        max = areacode[i + 1];
                    }
                    if (areacode[i] <= code && code < max)
                    {
                        return Encoding.Default.GetString(new byte[]
						{
							(byte)(65 + i)
						});
                    }
                }
                return "*";
            }
            return cnChar;
        }
    }
}
